/********************* 显示函数列表 *******************/
#include "lcd_opt.h"
#include "com_file_opt.h"
char *init_lcd(void)
{
	// 准备LCD屏幕
	int lcd = Open("/dev/fb0", O_RDWR);

	// 获取LCD设备的当前参数
	struct fb_var_screeninfo vinfo;
	ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);

	// 根据当前LCD设备参数申请适当大小的FRAMEBUFFR
	unsigned long bpp = vinfo.bits_per_pixel;
	char *FB = mmap(NULL, vinfo.xres * vinfo.yres * bpp/8,
		  		PROT_READ|PROT_WRITE, MAP_SHARED, lcd, 0);
	if(FB == MAP_FAILED)
	{
		perror("mmap() failed");
		exit(0);
	}

	return FB;
}

void show_someone(char *FB, int id)
{
	static int firsttime = 1;

	int namelen = 16;
	static char *oldfile = NULL;
	static char *newfile = NULL;

	if(firsttime == 1)
	{
		oldfile = calloc(1, namelen);
		newfile = calloc(1, namelen);

		snprintf(oldfile, namelen, "./jpg/%d.jpg", id);
		snprintf(newfile, namelen, "./jpg/%d.jpg", id);

		printf("[%d]: %s\n", __LINE__, newfile);
		show_in(FB, newfile);

		firsttime = 0;
		return;
	}

	snprintf(newfile, namelen, "./jpg/%d.jpg", id);
	fade_out(FB, oldfile);
	show_in (FB, newfile);

	return;
}

void show_in(char *FB, char *filename)
{
	char *rgb_buf = get_rgb(filename);
	blind_window_in(FB, (stride)rgb_buf);
	free(rgb_buf);
}

void fade_out(char *FB, char *filename)
{
	char *rgb_buf = get_rgb(filename);
	blind_window_out(FB, (stride)rgb_buf);
	free(rgb_buf);
}



// 将jpeg文件的压缩图像数据读出，放到jpg_buffer中去等待解压
unsigned long read_image_from_file(int fd,
				   unsigned char *jpg_buffer,
				   unsigned long jpg_size)
{
	unsigned long nread = 0;
	unsigned long total = 0;

	while(jpg_size > 0)
	{
		nread = read(fd, jpg_buffer, jpg_size);
		if(nread == -1)
		{
			perror("read jpeg-file failed");
			exit(1);
		}

		jpg_size -= nread;
		jpg_buffer += nread;
		total += nread;
	}
	close(fd);

	return total;
}

char *transfor(unsigned char *rgb_buffer)
{
	char *rgb_buf = calloc(1, 800*480*4);
	unsigned char *tmp = rgb_buffer + 1;

	int offset[6][3] = {
						{0,1,2},
						{0,2,1},
						{1,0,2},
						{1,2,0},
						{2,0,1},
						{2,1,0},
	};

	int i, j;
	static int n = 0;
	for(i=0; i<480; i++)
	{
		for(j=0; j<800; j++)
		{
			memcpy(rgb_buf+(j+800*i)*4+0, tmp+(j+800*i)*3+offset[2][0], 1);	
			memcpy(rgb_buf+(j+800*i)*4+1, tmp+(j+800*i)*3+offset[2][1], 1);	
			memcpy(rgb_buf+(j+800*i)*4+2, tmp+(j+800*i)*3+offset[2][2], 1);	
		}
	}
	printf("--->> n:%d <<---\n", n);
	n++;
	free(rgb_buffer);
	return rgb_buf;
}

char *get_rgb(char *filename)
{
	// 读取图片文件属性信息
	// 并根据其大小分配内存缓冲区jpg_buffer
	struct stat file_info;
	stat(filename, &file_info);
	int fd = Open(filename, O_RDONLY);

	unsigned char *jpg_buffer;
	jpg_buffer = (unsigned char *)calloc(1, file_info.st_size);
	read_image_from_file(fd, jpg_buffer, file_info.st_size);

	// 声明解压缩结构体，以及错误管理结构体
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;

	// 使用缺省的出错处理来初始化解压缩结构体
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);

	// 配置该cinfo，使其从jpg_buffer中读取jpg_size个字节
	// 这些数据必须是完整的JPEG数据
	jpeg_mem_src(&cinfo, jpg_buffer, file_info.st_size);

	// 读取JPEG文件的头，并判断其格式是否合法
	int ret = jpeg_read_header(&cinfo, true);
	if(ret != 1)
	{
		fprintf(stderr, "[%d]: jpeg_read_header failed: "
			"%s\n", __LINE__, strerror(errno));
		exit(1);
	}

	// 开始解压
	jpeg_start_decompress(&cinfo);

	int row_stride = cinfo.output_width * cinfo.output_components;

	// 根据图片的尺寸大小，分配一块相应的内存rgb_buffer
	// 用来存放从jpg_buffer解压出来的图像数据
	unsigned long rgb_size;
	unsigned char *rgb_buffer;
	rgb_size = row_stride * cinfo.output_height;
	rgb_buffer = (unsigned char *)calloc(1, rgb_size);

	// 循环地将图片的每一行读出并解压到rgb_buffer中
	while(cinfo.output_scanline < cinfo.output_height)
	{
		unsigned char *buffer_array[1];
		buffer_array[0] = rgb_buffer +
				(cinfo.output_scanline) * row_stride;
		jpeg_read_scanlines(&cinfo, buffer_array, 1);
	}

	// 解压完了，将jpeg相关的资源释放掉
 	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	free(jpg_buffer);

	return transfor(rgb_buffer);
}



//百叶窗多线程函数
void *__routine(void *p)
{
	struct argument *arg = (struct argument *)p;

	int i;

	if(arg->flag == IN)
	{
		for(i=HEIGHT/BLIND-1; i>=0; i--)
		{
			memcpy(&(arg->FB)[arg->offset+i][0],
		 	       &(arg->image)[arg->offset+i][0],
			       WIDTH*4);

			usleep(10000);
		}
	}

	if(arg->flag == OUT)
	{
		for(i=0; i<HEIGHT/BLIND; i++)
		{
			memset(&(arg->FB)[arg->offset+i][0], 0, WIDTH*4);

			usleep(10000);
		}
	}

	pthread_exit(NULL);
}

void __write_lcd(char *FB, unsigned long (*image)[WIDTH], int flag)
{
	int i;
	pthread_t tid[BLIND];
	for(i=0; i<BLIND; i++)
	{
		struct argument *arg =
				malloc(sizeof(struct argument));
		arg->FB = (stride)FB;
		arg->image = image;
		arg->offset = i*(HEIGHT/BLIND);
		arg->flag = flag;

		pthread_create(&tid[i], NULL, __routine, (void *)arg);
	}

	for(i=0; i<BLIND; i++)
	{
		pthread_join(tid[i], NULL);
	}
}

void blind_window_in(char *FB, unsigned long (*image)[WIDTH])
{
	__write_lcd(FB, image, IN); 
}

void blind_window_out(char *FB, unsigned long (*image)[WIDTH])
{
	__write_lcd(FB, image, OUT); 
}

void blind_window(char *FB, unsigned long (*image)[WIDTH])
{
	blind_window_in(FB, image);
	blind_window_out(FB, image);
}
